package com.weishi.project.speedometer.service.impl;

import com.weishi.common.utils.GPSUtil;
import com.weishi.project.speedometer.domain.EmaFilter;
import com.weishi.project.speedometer.service.IMantianxingService;
import com.weishi.project.speedometer.vo.MantianxingGpsVo;
import com.weishi.project.speedometer.vo.PropellerFrequencyData;
import com.weishi.project.speedometer.vo.PropellerFrequencyDataVo;
import com.weishi.project.training.domain.ShipSpeedRecordLog;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class MantianxingServiceImpl implements IMantianxingService {

    private Map<String,List<MantianxingGpsVo>> queue = new HashMap<>();

    @Override
    public void addTempList(MantianxingGpsVo vo) {
        List<MantianxingGpsVo> list = queue.get(vo.getDeviceId());
        if(list==null){
            list = new ArrayList<>();
            queue.put(vo.getDeviceId(),list);
        }
        calculateDistance(list,vo);
        list.add(vo);
    }

    @Override
    public void clearTempList(String deviceId) {
        List<MantianxingGpsVo> list = queue.get(deviceId);
        list.clear();
    }

    @Override
    public List<MantianxingGpsVo> getList(String deviceId) {
        List<MantianxingGpsVo> list = queue.get(deviceId);
        if(list==null) list = new ArrayList<>();
        return list;
    }

    /**
     * 计算距离
     */
    private void calculateDistance(List<MantianxingGpsVo> queue,MantianxingGpsVo vo){
        if(queue.size()==0){
            vo.setDistance(0.0);
            vo.setDistanceTotal(0.0);
            vo.setSpeedTodistance(0.0);
        }else{
            //初始点
            Double lat1 = queue.get(0).getB();
            Double lng1 = queue.get(0).getL();

            //上一点
            Double latbe = queue.get(queue.size()-1).getB();
            Double lngbe = queue.get(queue.size()-1).getL();

            long timeTempbe = queue.get(queue.size()-1).getTimeTimp();
            long timeTemp = vo.getTimeTimp();
            long time = timeTemp-timeTempbe;

            //数据转换(经纬度-距离)
            double mm1 = GPSUtil.GetDistance1(lat1, lng1, vo.getB(), vo.getL());
            double mmbe = GPSUtil.GetDistance1(latbe, lngbe, vo.getB(), vo.getL());
            vo.setDistance(mm1);
            /*double speedTodistance = time == 0?vo.getSpeed() : mmbe/(time/1000.0);
            if(speedTodistance-vo.getSpeed()>2){
                speedTodistance = vo.getSpeed();
            }
            vo.setSpeedTodistance(speedTodistance);*/
            vo.setSpeedTodistance(mmbe);
            vo.setDistanceTotal(queue.get(queue.size()-1).getDistanceTotal()+mmbe);
        }
    }

    /**
     * 根据速度曲线计算桨频
     * @param dataVos
     */
    @Override
    public List<PropellerFrequencyData> getPropellerFrequencyData(List<MantianxingGpsVo> dataVos, int count) {
        List<PropellerFrequencyDataVo> list = getImportantPoint(dataVos);
        List<PropellerFrequencyData> ret = new ArrayList<>();

        for (int i = 0; i < list.size(); i++) {
            PropellerFrequencyData data = new PropellerFrequencyData();
            data.setCount(count);
            if (list.get(i).getType() == -1) {
                data.setStartTime(list.get(i).getRealTime());
                data.setStartTimeTimp(list.get(i).getTimeTimp());

                if ((i + count * 2) < list.size()) {
                    data.setDistanceTotal(list.get(i + count * 2).getDistanceTotal());
                    data.setDistance(list.get(i + count * 2).getDistanceTotal() - list.get(i).getDistanceTotal());
                    data.setEndTime(list.get(i + count * 2).getRealTime());
                    data.setEndTimeTimp(list.get(i + count * 2).getTimeTimp());
                    double minute = (data.getEndTimeTimp() - data.getStartTimeTimp()) / 1000.0;
                    double averagePropeller = count / (minute / 60.0);
                    if(averagePropeller>150){
                        averagePropeller = 140;
                    }
                    data.setAveragePropeller(averagePropeller);
                } else {
                    PropellerFrequencyDataVo temp = (i + count * 2) <= list.size() ? list.get(i + count) : list.get(i);
                    data.setEndTime(temp.getRealTime());
                    data.setEndTimeTimp(temp.getTimeTimp());
                    data.setDistanceTotal(temp.getDistanceTotal());
                    data.setDistance(temp.getDistanceTotal() - list.get(i).getDistanceTotal());
                    double minute = (data.getEndTimeTimp() - data.getStartTimeTimp()) / 60000.0;
                    double averagePropeller = minute != 0 ? 1 / minute : 0.0;
                    if(averagePropeller>150){
                        averagePropeller = 140;
                    }
                    data.setAveragePropeller(averagePropeller);
                }
                data.setRealTime(data.getEndTime());

                ret.add(data);
            }
        }
        return ret;
    }

    @Override
    public List<PropellerFrequencyData> getPropellerFrequencyData(List<ShipSpeedRecordLog> dataVos) {
        List<PropellerFrequencyDataVo> list = getImportantPoint1(dataVos);
        List<PropellerFrequencyData> ret = new ArrayList<>();
        int count = 2;

        for (int i = 0; i < list.size(); i++) {
            PropellerFrequencyData data = new PropellerFrequencyData();
            data.setCount(count);
            if (list.get(i).getType() == -1) {
                data.setStartTime(list.get(i).getRealTime());
                data.setStartTimeTimp(list.get(i).getTimeTimp());

                if ((i + count * 2) < list.size()) {
                    data.setDistanceTotal(list.get(i + count * 2).getDistanceTotal());
                    data.setDistance(list.get(i + count * 2).getDistanceTotal() - list.get(i).getDistanceTotal());
                    data.setEndTime(list.get(i + count * 2).getRealTime());
                    data.setEndTimeTimp(list.get(i + count * 2).getTimeTimp());
                    double minute = (data.getEndTimeTimp() - data.getStartTimeTimp()) / 1000.0;
                    double averagePropeller = count / (minute / 60.0);
                    if(averagePropeller>150){
                        averagePropeller = 140;
                    }
                    data.setAveragePropeller(averagePropeller);
                } else {
                    PropellerFrequencyDataVo temp = (i + count * 2) <= list.size() ? list.get(i + count) : list.get(i);
                    data.setEndTime(temp.getRealTime());
                    data.setEndTimeTimp(temp.getTimeTimp());
                    data.setDistanceTotal(temp.getDistanceTotal());
                    data.setDistance(temp.getDistanceTotal() - list.get(i).getDistanceTotal());
                    double minute = (data.getEndTimeTimp() - data.getStartTimeTimp()) / 60000.0;
                    double averagePropeller = minute != 0 ? 1 / minute : 0.0;
                    if(averagePropeller>150){
                        averagePropeller = 140;
                    }
                    data.setAveragePropeller(averagePropeller);
                }
                data.setRealTime(data.getEndTime());

                ret.add(data);
            }
        }
        return ret;
    }

    /**
     * 获取波峰波谷
     *
     * @param dataVos
     * @return
     */
    private List<PropellerFrequencyDataVo> getImportantPoint(List<MantianxingGpsVo> dataVos) {
        List<PropellerFrequencyDataVo> dataVoList = null;
        try {
            dataVoList = new ArrayList<>();

            List<Double> distances = new ArrayList<>();
            for (MantianxingGpsVo gpsVo : dataVos) {
                distances.add(gpsVo.getSpeed());
            }
            double[] data = new double[dataVos.size()];
            int index = 0;
            for (Double aa : distances) {
                data[index++] = aa;
            }
            int peak = 0;

            try {
                int[] PeakAndTrough = new int[data.length];

                //需要三个不同的值进行比较，取lo,mid，hi分别为三值
                for (int lo = 0, mid = 1, hi = 2; hi < data.length; hi++) {
                    //先令data[lo]不等于data[mid]
                    while (mid < data.length && data[mid] == data[lo]) {
                        mid++;
                    }

                    hi = mid + 1;

                    //令data[hi]不等于data[mid]
                    while (hi < data.length && data[hi] == data[mid]) {
                        hi++;
                    }

                    if (hi >= data.length) {
                        break;
                    }

                    //检测是否为峰值
                    if (data[mid] > data[lo] && data[mid] > data[hi]) {
                        PeakAndTrough[mid] = 1;       //1代表波峰
                    } else if (data[mid] < data[lo] && data[mid] < data[hi]) {
                        PeakAndTrough[mid] = -1;      //-1代表波谷
                    }

                    lo = mid;
                    mid = hi;
                }

                //计算均值
                float ave = 0;
                for (int i = 0; i < data.length; i++) {
                    ave += data[i];
                }
                ave /= data.length;

                //排除大于均值的波谷和小于均值的波峰
                for (int i = 0; i < PeakAndTrough.length; i++) {
                    if ((PeakAndTrough[i] > 0 && data[i] < ave) || (PeakAndTrough[i] < 0 && data[i] > ave)) {
                        PeakAndTrough[i] = 0;
                    }
                }

                //统计波谷数量
                for (int i = 0; i < PeakAndTrough.length; i++) {
                    if (PeakAndTrough[i] != 0) {
                        PropellerFrequencyDataVo vo = new PropellerFrequencyDataVo();
                        vo.setType(PeakAndTrough[i]);
                        vo.setRealTime(dataVos.get(i).getLocalTime());
                        vo.setTimeTimp(dataVos.get(i).getTimeTimp());
                        vo.setDistanceTotal(dataVos.get(i).getDistanceTotal());
                        dataVoList.add(vo);
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataVoList;
    }

    private List<PropellerFrequencyDataVo> getImportantPoint1(List<ShipSpeedRecordLog> dataVos) {
        List<PropellerFrequencyDataVo> dataVoList = null;
        try {
            dataVoList = new ArrayList<>();

            List<Double> distances = new ArrayList<>();
            ShipSpeedRecordLog pre = dataVos.get(0);
            for (ShipSpeedRecordLog gpsVo : dataVos) {

                double time = (Long.parseLong(gpsVo.getTimp())-Long.parseLong(pre.getTimp()))/1000.0;
                if(time==0) continue;
                Double distance = gpsVo.getDistance()-pre.getDistance();
                if(distance<=0.01){
                    continue;
                }
//                Double speed = distance/time;
                Double speed = gpsVo.getSpeed();

                distances.add(speed);
                pre = gpsVo;
            }

            //指数滤波(EMA)
            //distances = EmaFilter.ema(distances, 0);

            double[] data = new double[dataVos.size()];
            int index = 0;
            for (Double aa : distances) {
                data[index++] = aa;
            }
            int peak = 0;

            try {
                int[] PeakAndTrough = new int[data.length];

                //需要三个不同的值进行比较，取lo,mid，hi分别为三值
                for (int lo = 0, mid = 1, hi = 2; hi < data.length; hi++) {
                    //先令data[lo]不等于data[mid]
                    while (mid < data.length && data[mid] == data[lo]) {
                        mid++;
                    }

                    hi = mid + 1;

                    //令data[hi]不等于data[mid]
                    while (hi < data.length && data[hi] == data[mid]) {
                        hi++;
                    }

                    if (hi >= data.length) {
                        break;
                    }

                    //检测是否为峰值
                    if (data[mid] > data[lo] && data[mid] > data[hi]) {
                        PeakAndTrough[mid] = 1;       //1代表波峰
                    } else if (data[mid] < data[lo] && data[mid] < data[hi]) {
                        PeakAndTrough[mid] = -1;      //-1代表波谷
                    }

                    lo = mid;
                    mid = hi;
                }

                //计算均值
                float ave = 0;
                for (int i = 0; i < data.length; i++) {
                    ave += data[i];
                }
                ave /= data.length;

                //排除大于均值的波谷和小于均值的波峰
                for (int i = 0; i < PeakAndTrough.length; i++) {
                    if ((PeakAndTrough[i] > 0 && data[i] < ave) || (PeakAndTrough[i] < 0 && data[i] > ave)) {
                        PeakAndTrough[i] = 0;
                    }
                }

                //统计波谷数量
                for (int i = 0; i < PeakAndTrough.length; i++) {
                    if (PeakAndTrough[i] != 0) {
                        PropellerFrequencyDataVo vo = new PropellerFrequencyDataVo();
                        vo.setType(PeakAndTrough[i]);
                        vo.setRealTime(dataVos.get(i).getUtc());
                        vo.setTimeTimp(Long.parseLong(dataVos.get(i).getTimp()));
                        vo.setDistanceTotal(dataVos.get(i).getDistance());
                        dataVoList.add(vo);
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataVoList;
    }

}
